﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Xtee.Core.Strings
{
    ///borrowed from : http://haacked.com/archive/2009/01/04/fun-with-named-formats-string-parsing-and-edge-cases.aspx
    public  class TokenFormatter
    {
        private readonly string _format;

        public TokenFormatter(string format)
        {
            if (format == null)
            {
                throw new ArgumentNullException("format");
            }
            _format = format;
        }

        public  string Inject(object source)
        {

            var formattedStrings = (from expression in SplitFormat()
                                    select expression.Eval(source)).ToArray();
            return String.Join("", formattedStrings);
        }

        public IEnumerable<string> KeywordsUsed
        {
            get
            {
                return SplitFormat().OfType<FormatExpression>().Select(x=>x.Expression);
            }
        }

        private   IEnumerable<ITextExpression> SplitFormat()
        {
            int exprEndIndex = -1;
            int expStartIndex;

            do
            {
                expStartIndex = IndexOfExpressionStart(exprEndIndex + 1);
                if (expStartIndex < 0)
                {
                    //everything after last end brace index.
                    if (exprEndIndex + 1 < _format.Length)
                    {
                        yield return new LiteralFormat(
                            _format.Substring(exprEndIndex + 1));
                    }
                    break;
                }

                if (expStartIndex - exprEndIndex - 1 > 0)
                {
                    //everything up to next start brace index
                    yield return new LiteralFormat(_format.Substring(exprEndIndex + 1
                      , expStartIndex - exprEndIndex - 1));
                }

                int endBraceIndex =  IndexOfExpressionEnd(expStartIndex + 1);
                if (endBraceIndex < 0)
                {
                    //rest of string, no end brace (could be invalid expression)
                    yield return new FormatExpression(_format.Substring(expStartIndex));
                }
                else
                {
                    exprEndIndex = endBraceIndex;
                    //everything from start to end brace.
                    yield return new FormatExpression(_format.Substring(expStartIndex
                      , endBraceIndex - expStartIndex + 1));

                }
            } while (expStartIndex > -1);
        }
         
        int IndexOfExpressionStart(int startIndex)
        {
            int index = _format.IndexOf('[', startIndex);
            if (index == -1)
            {
                return index;
            }

            //peek ahead.
            if (index + 1 < _format.Length)
            {
                char nextChar = _format[index + 1];
                if (nextChar == '[')
                {
                    return IndexOfExpressionStart( index + 2);
                }
            }

            return index;
        }

        int IndexOfExpressionEnd(int startIndex)
        {
            int endBraceIndex = _format.IndexOf(']', startIndex);
            if (endBraceIndex == -1)
            {
                return endBraceIndex;
            }
            //start peeking ahead until there are no more braces...
            // }}}}
            int braceCount = 0;
            for (int i = endBraceIndex + 1; i < _format.Length; i++)
            {
                if (_format[i] == ']')
                {
                    braceCount++;
                }
                else
                {
                    break;
                }
            }
            if (braceCount % 2 == 1)
            {
                return IndexOfExpressionEnd(endBraceIndex + braceCount + 1);
            }

            return endBraceIndex;
        }
    }
}
